/*
 * console.c
 *
 *  Created on: 2017年3月21日
 *      Author: zhikang.peng
 */
#include <string.h>
#include <stdio.h>
#include "console.h"
#include "memory.h"
#include "file.h"
#include "graphic.h"
#include "keyboard.h"
#include "naskfunc.h"
#include "timer.h"
#include "window.h"
#include "dsctbl.h"
#include "sheet.h"
#include "mtask.h"

extern struct TASKCTL *taskctl;

void console_task(struct SHEET *sheet, unsigned int memtotal) {
	struct TASK *task = task_now();
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880);
	struct CONSOLE cons = cons_init(sheet, 8, 28, -1);
	char cmdline[30];
	struct FILEHANDLE fhandle[8];
	unsigned char *language = (char *) *((int *) 0x0fe8);

	task->cons = &cons;
	task->cmdline = cmdline;
	if (cons.sht != 0) {
		cons.timer = timer_alloc();
		timer_init(cons.timer, task->fifo, 1);
		timer_settime(cons.timer, 50);
	}

	file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200));
	for (i = 0; i < 8; i++) {
		fhandle[i].buf = 0;
	}
	task->fhandle = fhandle;
	task->fat = fat;
    if (language[4096] != 0xff) {
		task->langmode = 1;
	} else {
		task->langmode = 0;
	}
	task->sbcCaseByteOne = 0;

	cons_putchar(&cons, '>', 1); // 提示符

	for (;;) {
		io_cli();
		if (fifo32_status(task->fifo) == 0) {
			task_sleep(task);
			io_sti();
		} else {
			i = fifo32_get(task->fifo);
			io_sti();
			if (i <= 1 && cons.sht != 0) {
				if (i != 0) {
					timer_init(cons.timer, task->fifo, 0);
					if (cons.cursor_c >= 0) {
						cons.cursor_c = COL8_FFFFFF;
					}
				} else {
					timer_init(cons.timer, task->fifo, 1);
					if (cons.cursor_c >= 0) {
						cons.cursor_c = COL8_000000;
					}
				}
				timer_settime(cons.timer, 50);
			}
			if (i == CURSOR_FLASH) { // 显示光标
				cons.cursor_c = COL8_FFFFFF;
			}
			if (i == CURSOR_NOT_FLASH) { //不显示光标
				if (cons.sht != 0) {
					boxfill8(cons.sht->buf, cons.sht->bxsize, COL8_000000, cons.cursor_x, cons.cursor_y, cons.cursor_x + 7, cons.cursor_y + 15);
				}
				cons.cursor_c = -1;
			}
			if (i == 4) { // 关闭命令行
				cmd_exit(&cons, fat);
			}

			if (256 <= i && i <= 511) { // 键盘数据
				if (i == 8 + 256) { // 退格键
					if (cons.cursor_x > 16) {
						// 用空白擦字符后将光标前移一位
						cons_putchar(&cons, ' ', 0);
						cons.cursor_x -= 8;
					}
				} else if (i == 10 + 256) { // Enter
					cons_putchar(&cons, ' ', 0); // 用空格将光标擦除
					cmdline[cons.cursor_x / 8 - 2] = 0;
					cons_newline(&cons);
					cons_runcmd(cmdline, &cons, fat, memtotal);
					if (cons.sht == 0) {
						cmd_exit(&cons, fat);
					}
					cons_putchar(&cons, '>', 1);
				} else {
					if (cons.cursor_x < 240) {
						// 显示一个字符后光标后移一位
						cmdline[cons.cursor_x / 8 - 2] = i - 256;
						cons_putchar(&cons, i - 256, 1);
					}
				}
			}
			if (cons.sht != 0) {
				//重新设置光标
				if (cons.cursor_c >= 0) {
					boxfill8(cons.sht->buf, cons.sht->bxsize, cons.cursor_c, cons.cursor_x, cons.cursor_y, cons.cursor_x + 7, cons.cursor_y + 15);
				}
				sheet_refresh(cons.sht, cons.cursor_x, cons.cursor_y, cons.cursor_x + 8, cons.cursor_y + 16);
			}
		}
	}
}

struct CONSOLE cons_init(struct SHEET *sheet, int cursor_x, int cursor_y, int cursor_c) {
	struct CONSOLE cons;
	cons.sht = sheet;
	cons.cursor_x = cursor_x;
	cons.cursor_y = cursor_y;
	cons.cursor_c = cursor_c;
	return cons;
}

/**
 * 显示字符
 */
void cons_putchar(struct CONSOLE *cons, int c, char move) {
	char s[2];
	s[0] = c;
	s[1] = 0;
	if (s[0] == 0x09) { // 制表符
		for (;;) {
			if (cons->sht != 0) {
				putfonts8_asc_sht(cons->sht, cons->cursor_x, cons->cursor_y, COL8_FFFFFF, COL8_000000, " ", 1);
			}
			cons->cursor_x += 8;
			if (cons->cursor_x == 8 + 240) {
				cons_newline(cons);
			}
			if (((cons->cursor_x - 8) & 0x1f) == 0) {
				break; //被32整除则break
			}
		}
	} else if (s[0] == 0x0a) {
		cons_newline(cons);
	} else if (s[0] == 0x0d) {
		//do nothing
	} else {
		if (cons->sht != 0) {
			putfonts8_asc_sht(cons->sht, cons->cursor_x, cons->cursor_y, COL8_FFFFFF, COL8_000000, s, 1);
		}
		if (move != 0) { // move为0时光标不后移
			cons->cursor_x += 8;
			if (cons->cursor_x == 8 + 240) {
				cons_newline(cons);
			}
		}
	}
}

/**
 * 换行
 */
void cons_newline(struct CONSOLE *cons) {
	int x, y;
	struct SHEET *sheet = cons->sht;
	struct TASK *task = task_now();

	if (cons->cursor_y < 28 + 112) {
		cons->cursor_y += 16;
	} else {
		if (sheet != 0) {
			for (y = 28; y < 28 + 112; y++) {
				for (x = 8; x < 8 + 240; ++x) {
					sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize];
				}
			}
			for (y = 28 + 112; y < 28 + 128; y++) {
				for (x = 8; x < 8 + 240; ++x) {
					sheet->buf[x + y * sheet->bxsize] = COL8_000000;
				}
			}
			sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
		}
	}
	cons->cursor_x = 8;
	if (task->langmode == 1 && task->sbcCaseByteOne != 0) {
		cons->cursor_x = 16;
	}
}

/**
 * 显示字符串
 */
void cons_putstr(struct CONSOLE *cons, char *s) {
	for (; *s != 0; s++) {
		cons_putchar(cons, *s, 1);
	}
}

/**
 * 显示指定长度的字符串
 */
void cons_putstrlen(struct CONSOLE *cons, char *s, int len) {
	int i;
	for (i = 0; i < len; i++) {
		cons_putchar(cons, s[i], 1);
	}
}

void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal) {
	if (strcmp(cmdline, "mem") == 0 && cons->sht != 0) {
		cmd_mem(cons, memtotal);
	} else if (strcmp(cmdline, "cls") == 0 && cons->sht != 0) {
		cmd_cls(cons);
	} else if (strcmp(cmdline, "dir") == 0 && cons->sht != 0) {
		cmd_dir(cons);
	} else if (strncmp(cmdline, "type", 4) == 0 && cons->sht != 0) {
		cmd_type(cons, fat, cmdline);
	} else if (strcmp(cmdline, "exit") == 0) {
		cmd_exit(cons, fat);
	} else if (strncmp(cmdline, "start", 5) == 0) {
		cmd_start(cons, cmdline, memtotal);
	} else if (strncmp(cmdline, "ncst", 4) == 0) {
		cmd_ncst(cons, cmdline, memtotal);
	} else if (strncmp(cmdline, "cmd", 3) == 0) { // 还不成熟，有重大bug
		cmd_cmd(cons, cmdline, memtotal);
	} else if (strncmp(cmdline, "langmode", 8) == 0) {
		cmd_langmode(cons, cmdline);
	} else if (cmdline[0] != 0) {
		if (cmd_app(cons, fat, cmdline) == 0) {
			// 不是命令也不是空行
			cons_putstr(cons, "Bad command.\n\n");
		}
	}
}

void cmd_mem(struct CONSOLE *cons, unsigned int memtotal) {
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	char s[60];
	// mem命令
	sprintf(s, "total %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024);
	cons_putstr(cons, s);
}

void cmd_cls(struct CONSOLE *cons) {
	int x, y;
	struct SHEET *sheet = cons->sht;
	for (y = 28; y < 28 + 128; y++) {
		for (x = 8; x < 8 + 240; ++x) {
			sheet->buf[x + y * sheet->bxsize] = COL8_000000;
		}
	}
	sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
	cons->cursor_y = 28;
}

void cmd_dir(struct CONSOLE *cons) {
	struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600);
	int x, y;
	char s[30];
	for (x = 0; x < 224; ++x) {
		if (finfo[x].name[0] == 0x00) {
			break;
		}
		if (finfo[x].name[0] != 0xe5) { //文件还存在
			if ((finfo[x].type & 0x18) == 0) {
				sprintf(s, "filename.ext  %7d\n", finfo[x].size);
				for (y = 0; y < 8; y++) {
					s[y] = finfo[x].name[y];
				}
				s[9] = finfo[x].ext[0];
				s[10] = finfo[x].ext[1];
				s[11] = finfo[x].ext[2];
				cons_putstr(cons, s);
			}
		}
	}
	cons_newline(cons);

}

void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline) {
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	struct FILEINFO *finfo = file_search(cmdline + 5, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
	char *p;
	if (finfo != 0) {
		// 找到文件的情况
		p = (char *) memman_alloc_4k(memman, finfo->size);
		file_load(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x3e00));
		cons_putstrlen(cons, p, finfo->size);
		memman_free_4k(memman, (int) p, finfo->size);
	} else {
		cons_putstr(cons, "File not found.\n");
	}
	cons_newline(cons);
}

void cmd_exit(struct CONSOLE *cons, int *fat) {
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	struct TASK *task = task_now();
	struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
	struct FIFO32 *fifo = (struct FIFO32 *) *((int *) 0x0fec);
	if (cons->sht != 0) {
		timer_cancel(cons->timer);
	}
	memman_free_4k(memman, (int) fat, 4 * 2880);
	io_cli();
	//	发送数据让task_a帮忙关闭命令行
	if (cons->sht != 0) {
		fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); //768~1024
	} else {
		fifo32_put(fifo, task - taskctl->tasks0 + 1024); // 1024~2023
	}
	io_sti();
	for (;;) {
		task_sleep(task);
	}
}

void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal) {
	struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
	struct SHEET *sht = open_console(shtctl, memtotal);
	struct FIFO32 *fifo = sht->task->fifo;
	int i;

	keywin_off(cons->sht);
	sheet_slide(sht, cons->sht->vx0 * 2, cons->sht->vy0 * 2);
	sheet_updown(sht, shtctl->top);
	keywin_on(sht);
	for (i = 6; cmdline[i] != 0; i++) {
		fifo32_put(fifo, cmdline[i] + 256);
	}
	fifo32_put(fifo, 10 + 256);
	cons_newline(cons);
}

/**
 * 不显示命令行执行命令
 */
void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal) {
	struct TASK *task = open_constask(0, memtotal);
	struct FIFO32 *fifo = task->fifo;
	int i;

	for (i = 5; cmdline[i] != 0; i++) {
		fifo32_put(fifo, cmdline[i] + 256);
	}
	fifo32_put(fifo, 10 + 256);
	cons_newline(cons);
}

void cmd_cmd(struct CONSOLE *cons, char *cmdline, int memtotal) {
	struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0xfe4);
	struct SHEET *sheet = open_console(shtctl, memtotal);
	int i;

	keywin_off(cons->sht);
	sheet_slide(sheet, cons->sht->vx0 * 2, cons->sht->vy0 * 2);
	sheet_updown(sheet, shtctl->top);
	keywin_on(sheet);
	for (i = 4; cmdline[i] != 0; i++) {
		fifo32_put(sheet->task->fifo, cmdline[i] + 256);
	}
	fifo32_put(sheet->task->fifo, 10 + 256);
	cons_newline(cons);
}

void cmd_langmode(struct CONSOLE *cons, char *cmdline) {
	struct TASK *task = task_now();
	unsigned char mode = cmdline[9] - '0';
	if (mode <= 2) {
		task->langmode = mode;
	} else {
		cons_putstr(cons, "mode number error.\n");
	}
	cons_newline(cons);
}

/**
 * 执行外部程序
 */
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) {
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	//struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
	struct FILEINFO *finfo;
	struct SHTCTL *shtctl;
	struct SHEET *sht;

	char name[18], *p, *q;
	struct TASK *task = task_now();
	int i, segsize, datasize, esp, datahrb;

	for (i = 0; i < 13; ++i) {
		if (cmdline[i] <= ' ') {
			break;
		}
		name[i] = cmdline[i];
	}
	name[i] = 0;
	finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
	if (finfo == 0 && name[i - 1] != '.') {
		name[i] = '.';
		name[i + 1] = 'H';
		name[i + 2] = 'R';
		name[i + 3] = 'B';
		name[i + 4] = 0;
		finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
	}

	if (finfo != 0) {
		// 找到文件的情况
		p = (char *) memman_alloc_4k(memman, finfo->size);
		file_load(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x3e00));
		if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) {
			segsize = *((int *) (p + 0x0000)); //数据段大小
			esp = *((int *) (p + 0x000c)); // 应用程序启动时esp寄存器的初始值
			datasize = *((int *) (p + 0x0010)); // 需要向数据段传送的字节数
			datahrb = *((int *) (p + 0x0014)); // 数据段传送的起始地址
			q = (char *) memman_alloc_4k(memman, segsize); // 应用程序数据段，栈内存空间
			task->ds_base = (int) q; // 数据段
			// 保护应用程序
			set_segmdesc(*task->ldt + 0, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60);
			set_segmdesc(*task->ldt + 1, segsize - 1, (int) q, AR_DATA32_RW + 0x60);
			for (i = 0; i < datasize; i++) { // 复制数据
				q[esp + i] = p[datahrb + i];
			}
			start_app(0x1b, 0 * 8 + 4, esp, 1 * 8 + 4, &(task->tss.esp0));
			//关闭不用的窗体
			shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
			for (i = 0; i < MAX_SHEETS; i++) {
				sht = &(shtctl->sheets0[i]);
				if ((sht->flags & 0x11) == 0x11 && sht->task == task) {
					sheet_free(sht);
				}
			}
			// 将未关闭的文件关闭
			for (i = 0; i < 8; i++) {
				if (task->fhandle[i].buf != 0) {
					memman_free_4k(memman, (int) task->fhandle[i].buf, task->fhandle[i].size);
					task->fhandle[i].buf = 0;
				}
			}
			timer_cancelall(task->fifo);
			memman_free_4k(memman, (int) q, segsize);
			task->sbcCaseByteOne = 0;
		} else {
			cons_putstr(cons, ".hrb file format error.\n");
		}
		memman_free_4k(memman, (int) p, finfo->size);
		cons_newline(cons);
		return 1;
	}
	return 0;
}

/**
 * 这个参数是汇编语言：pushad 的入栈顺序
 * EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI
 * 因为栈的顺序是后入先出，所以参数列表要反着写
 * edx:是系统程序号
 */
int *system_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) {
	struct TASK *task = task_now();
	int ds_base = task->ds_base;
	struct CONSOLE *cons = task->cons;
	struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
	struct FIFO32 *sys_fifo = (struct FIFO32 *) *((int *) 0xfec);
	struct SHEET *sht;
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	struct FILEINFO *finfo;
	struct FILEHANDLE *fh;
	int *reg = &eax + 1; //下标从7~0(eax-ecx-edx-ebx-esp-ebp-esi-edi)
	int data;

	if (edx == 0x1) { // 打印单字符
		cons_putchar(cons, eax & 0xff, 1);
	} else if (edx == 0x2) { //打印字符串
		cons_putstr(cons, (char *) ebx + ds_base);
	} else if (edx == 0x3) { //打印字符串
		cons_putstrlen(cons, (char *) ebx + ds_base, ecx);
	} else if (edx == 0x4) { //结束应用程序
		return &(task->tss.esp0);
	} else if (edx == 0x5) { //创建一个窗体
		sht = sheet_alloc(shtctl);
		sht->task = task;
		sht->flags |= 0x10; // 自动关闭窗体
		sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax);
		make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0);
		// 让窗体显示在中央
		sheet_slide(sht, ((shtctl->xsize - esi) / 2) & ~3, (shtctl->ysize - edi) / 2);
		sheet_updown(sht, shtctl->top); // 指定为鼠标图层的高度，鼠标移到上层
		reg[7] = (int) sht;
	} else if (edx == 0x6) { //在窗体上输出文字
		sht = (struct SHEET *) (ebx & 0xfffffffe); // ebx的地址是一个偶数,在app调用加一之后用与运算可以还原
		putfonts8_asc(sht->buf, sht->bxsize, esi, edi, eax, (char *) ebp + ds_base);
		if ((ebx & 1) == 0) { //偶数的第0位只能是0所以用与运算结果等于0
			sheet_refresh(sht, esi, edi, esi + ecx * 8, edi + 16);
		}
	} else if (edx == 0x7) { //绘制方块(图形)
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		boxfill8(sht->buf, sht->bxsize, ebp, eax, ecx, esi, edi);
		if ((ebx & 1) == 0) {
			sheet_refresh(sht, eax, ecx, esi + 1, edi + 1);
		}
	} else if (edx == 0x8) { //申请内存初始化
		memman_init((struct MEMMAN *) (ebx + ds_base));
		ecx &= 0xfffffff0;
		memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx);
	} else if (edx == 0x9) { //分配内存
		ecx = (ecx + 0x0f) & 0xfffffff0;
		reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx);
	} else if (edx == 0xa) { //释放内存
		ecx = (ecx + 0x0f) & 0xfffffff0;
		memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx);
	} else if (edx == 0xb) { //在窗口画点
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		sht->buf[sht->bxsize * edi + esi] = eax;
		if ((ebx & 1) == 0) {
			sheet_refresh(sht, esi, edi, esi + 1, edi + 1);
		}
	} else if (edx == 0xc) { //刷新窗体
		sht = (struct SHEET *) ebx;
		sheet_refresh(sht, eax, ecx, esi, edi);
	} else if (edx == 0xd) { //绘制直线
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		drawLine(sht, eax, ecx, esi, edi, ebp);
		if ((ebx & 1) == 0) {
			sheet_refresh(sht, eax, ecx, esi + 1, edi + 1);
		}
	} else if (edx == 0xe) { //关闭窗体
		sheet_free((struct SHEET *) ebx);
	} else if (edx == 0xf) { //接受键盘输入
		for (;;) {
			io_cli();
			if (fifo32_status(task->fifo) == 0) {
				if (eax != 0) {
					task_sleep(task);
				} else {
					io_sti();
					reg[7] = -1;
					return 0;
				}
			}
			data = fifo32_get(task->fifo);
			io_sti();
			if (data <= 1) { // 光标用定时器
				timer_init(cons->timer, task->fifo, 1);
				timer_settime(cons->timer, 50);
			}
			if (data == 2) { //光标ON
				cons->cursor_c = COL8_FFFFFF;
			}
			if (data == 3) { //光标OFF
				cons->cursor_c = -1;
			}
			if (data == 4) {
				timer_cancel(cons->timer);
				io_cli();
				fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024);
				cons->sht = 0;
				io_sti();
			}
			if (data >= 256) { //键盘数据
				reg[7] = data - 256;
				return 0;
			}
		}
	} else if (edx == 0x10) { //获取定时器
		reg[7] = (int) timer_alloc();
		((struct TIMER *) reg[7])->flags2 = 1;
	} else if (edx == 0x11) { //设置定时器的发送数据
		timer_init((struct TIMER *) ebx, task->fifo, eax + 256);
	} else if (edx == 0x12) { //定时器的时间设定
		timer_settime((struct TIMER *) ebx, eax);
	} else if (edx == 0x13) { //释放定时器
		timer_free((struct TIMER *) ebx);
	} else if (edx == 0x14) { // 蜂鸣器发声
		// eax表示声音的频率
		if (eax == 0) { // OFF
			data = io_in8(0x61);
			io_out8(0x61, data & 0x0d);
		} else { // ON
			// 音高设置
			data = 1193180000 / eax;
			io_out8(0x43, 0xb6);
			io_out8(0x42, data & 0xff); // data的低8位
			io_out8(0x42, data >> 8); //data的高8位
			// ON
			data = io_in8(0x61);
			io_out8(0x61, (data | 0x03) & 0x0f);
		}
	} else if (edx == 0x15) { // 打开文件
		for (data = 0; data < 8; ++data) {
			if (task->fhandle[data].buf == 0) {
				break;
			}
		}
		fh = &task->fhandle[data];
		reg[7] = 0;
		if (data < 8) {
			finfo = file_search((char *) ebx + ds_base, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
			if (finfo != 0) {
				reg[7] = (int) fh; // 返回文件句柄
				fh->buf = (char *) memman_alloc_4k(memman, finfo->size);
				fh->size = finfo->size;
				fh->pos = 0;
				file_load(finfo->clustno, finfo->size, fh->buf, task->fat, (char *) (ADR_DISKIMG + 0x003e00));
			}
		}
	} else if (edx == 0x16) { // 关闭文件
		fh = (struct FILEHANDLE *) eax;
		memman_free_4k(memman, (int) fh->buf, fh->size);
		fh->buf = 0;
	} else if (edx == 0x17) { // 文件定位
		fh = (struct FILEHANDLE *) eax;
		if (ecx == 0) {
			fh->pos = ebx;
		} else if (ecx == 1) {
			fh->pos += ebx;
		} else if (ecx == 2) {
			fh->pos = fh->size + ebx;
		}
		if (fh->pos < 0) {
			fh->pos = 0;
		}
		if (fh->pos > fh->size) {
			fh->pos = fh->size;
		}
	} else if (edx == 0x18) { // 文件大小
		fh = (struct FILEHANDLE *) eax;
		if (ecx == 0) {
			reg[7] = fh->size;
		} else if (ecx == 1) {
			reg[7] = fh->pos;
		} else if (ecx == 2) {
			reg[7] = fh->pos - fh->size;
		}
	} else if (edx == 0x19) { // 读取文件
		fh = (struct FILEHANDLE *) eax;
		for (data = 0; data < ecx; data++) {
			if (fh->pos == fh->size) {
				break;
			}
			*((char *) ebx + ds_base + data) = fh->buf[fh->pos];
			fh->pos++;
		}
		reg[7] = data;
	} else if (edx == 0x1a) { // 获取命令行
		data = 0;
		for (;;) {
			*((char *) ebx + ds_base + data) = task->cmdline[data];
			if (task->cmdline[data] == 0) {
				break;
			}
			if (data >= ecx) {
				break;
			}
			data++;
		}
		reg[7] = data;
	} else if (edx == 0x1b) {
		reg[7] = task->langmode;
	}
	return 0;
}

int *inthandler0c(int *esp) {
	struct TASK *task = task_now();
	struct CONSOLE *cons = task->cons;
	char s[30];
	cons_putstr(cons, "\nINT 0x0C : \nStack Exception.\n");
	sprintf(s, "EIP = 0x%08X\n", esp[11]);
	cons_putstr(cons, s);
	return &(task->tss.esp0);
}

/**
 * 处理中断
 */
int *inthandler0d(int *esp) {
	struct TASK *task = task_now();
	struct CONSOLE *cons = task->cons;
	char s[30];
	cons_putstr(cons, "\nINT 0x0D : \nGeneral Protected Exception.\n");
	sprintf(s, "EIP = 0x%08X\n", esp[11]);
	cons_putstr(cons, s);
	return &(task->tss.esp0);
}

/**
 * 打开一个新的命令行窗口
 */
struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal) {
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	struct SHEET *sht = sheet_alloc(shtctl);
	unsigned char *buf = (unsigned char*) memman_alloc_4k(memman, 256 * 165);

	sheet_setbuf(sht, buf, 256, 165, -1);
	make_window8(buf, 256, 165, "console", 0);
	make_textbox8(sht, 8, 28, 240, 128, COL8_000000);

	sht->task = open_constask(sht, memtotal);
	sht->flags |= 0x20; // 有光标

	return sht;
}

/**
 * 打开一个不显示窗体的任务
 */
struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal) {
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	struct TASK *task = task_alloc();
	int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4);

	task->cons_stack = memman_alloc_4k(memman, 64 * 1024);
	task->tss.esp = task->cons_stack + 64 * 1024 - 12;
	task->tss.eip = (int) &console_task;
	task->tss.es = 1 * 8;
	task->tss.cs = 2 * 8;
	task->tss.ss = 1 * 8;
	task->tss.ds = 1 * 8;
	task->tss.fs = 1 * 8;
	task->tss.gs = 1 * 8;
	*((int *) (task->tss.esp + 4)) = (int) sht; // 传参数
	*((int *) (task->tss.esp + 8)) = memtotal; // 传参数
	task_run(task, 2, 2);
	fifo32_init(task->fifo, 128, cons_fifo, task);
	return task;
}

void keywin_off(struct SHEET *key_win) {
	change_wtitle8(key_win, 0);
	if ((key_win->flags & 0x20) != 0) {
		fifo32_put(key_win->task->fifo, 3); //命令行光标OFF
	}
}

void keywin_on(struct SHEET *key_win) {
	change_wtitle8(key_win, 1);
	if ((key_win->flags & 0x20) != 0) {
		fifo32_put(key_win->task->fifo, 2); //命令行光标ON
	}
}

void close_constask(struct TASK *task) {
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	task_sleep(task);
	memman_free_4k(memman, task->cons_stack, 64 * 1024);
	memman_free_4k(memman, (int) task->fifo->buf, 128 * 4);
	memman_free_4k(memman, (int) task->fifo, sizeof(struct FIFO32));
	memman_free_4k(memman, (int) task->ldt[0], sizeof(struct SEGMENT_DESCRIPTOR));
	memman_free_4k(memman, (int) task->ldt[1], sizeof(struct SEGMENT_DESCRIPTOR));
	task->flags = TASK_INIT;
	task->fifo = 0;
}

void close_console(struct SHEET *sht) {
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	memman_free_4k(memman, (int) sht->buf, 256 * 165);
	sheet_free(sht);
	close_constask(sht->task);
}
